﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D10;

namespace DarkLight.Controls
{
    public class ViewPort : System.Windows.Media.Media3D10.Viewport3D10
    {
        #region DependencyProperties
        public static readonly DependencyProperty MinZoomProperty =
            DependencyProperty.RegisterAttached("MinZoom", typeof(double), typeof(ViewPort));

        public static readonly DependencyProperty MaxZoomProperty =
            DependencyProperty.RegisterAttached("MaxZoom", typeof(double), typeof(ViewPort));
        #endregion

        #region Public Static Methods
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011")]
        public static double GetMinZoom(Camera obj)
        {
            if (object.ReferenceEquals(obj, null))
                throw new ArgumentNullException("obj");

            return (double)obj.GetValue(MinZoomProperty);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011")]
        public static void SetMinZoom(Camera obj, double value)
        {
            if (object.ReferenceEquals(obj, null))
                throw new ArgumentNullException("obj");
            obj.SetValue(MinZoomProperty, value);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011")]
        public static double GetMaxZoom(Camera obj)
        {
            if (object.ReferenceEquals(obj, null))
                throw new ArgumentNullException("obj");
            return (double)obj.GetValue(MaxZoomProperty);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011")]
        public static void SetMaxZoom(Camera obj, double value)
        {
            if (object.ReferenceEquals(obj, null))
                throw new ArgumentNullException("obj");
            obj.SetValue(MaxZoomProperty, value);
        }
        #endregion
        
        #region Data
        private Storyboard _cameraRotationStoryboard;

        private const float WHELL_ZOOM_REDUCTION = 500.0f;
        private const float WHEEL_ROT_ANGULAR_SPEED = 1.0f;

        private Point _startPosition;
        #endregion

        #region Private Properties
        private Storyboard CameraAnimation
        {
            get
            {
                if (object.ReferenceEquals(this._cameraRotationStoryboard, null))
                    this._cameraRotationStoryboard = this.Resources["cameraRotationStoryboard"] as Storyboard;
                return this._cameraRotationStoryboard;
            }
        }
        #endregion

        #region Viewport3D10 Overrides
        protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnMouseDown(e);
            var mousePosition = e.GetPosition(this);

            if (e.RightButton == MouseButtonState.Pressed)
            {
                _startPosition = mousePosition;
            }
            Mouse.Capture(this);
        }

        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            base.OnMouseUp(e);
            Mouse.Capture(this, CaptureMode.None);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnMouseMove(e);
            if (Mouse.Captured == null)
                return;
            if (e.RightButton == MouseButtonState.Pressed)
            {
                Point currentPosition = e.GetPosition(this);
                SingleAnimation yawAnimation = this.CameraAnimation.Children[0] as SingleAnimation;
                SingleAnimation rollAnimation = this.CameraAnimation.Children[1] as SingleAnimation;

                Vector diff = _startPosition - currentPosition;

                Console.WriteLine("DiffX: " + diff.X);
                //yawAnimation.To = WHEEL_ROT_ANGULAR_SPEED * -1 * (float)diff.Y;
                rollAnimation.To = WHEEL_ROT_ANGULAR_SPEED * (float)diff.X;
                this.CameraAnimation.Begin();

                //_startPosition = currentPosition;
            }
        }

        protected override void OnMouseWheel(System.Windows.Input.MouseWheelEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnMouseWheel(e);

            SingleAnimation scaleX = this.CameraAnimation.Children[2] as SingleAnimation;
            SingleAnimation scaleY = this.CameraAnimation.Children[3] as SingleAnimation;
            SingleAnimation scaleZ = this.CameraAnimation.Children[4] as SingleAnimation;
            float zoom = scaleX.To.HasValue ? scaleX.To.Value : 1;
            
            float minZoom = (float)GetMinZoom(this.Camera);
            float maxZoom = (float)GetMaxZoom(this.Camera);

            if ((zoom == maxZoom && e.Delta < 0) || (zoom == minZoom && e.Delta > 0))
                return;

            float interval = -e.Delta / WHELL_ZOOM_REDUCTION;
            zoom += interval;
            if (zoom > maxZoom) zoom = maxZoom;
            if (zoom < minZoom) zoom = minZoom;

            scaleX.To = zoom;
            scaleY.To = zoom;
            scaleZ.To = zoom;
            this.CameraAnimation.Begin();
        }
        #endregion
    }
}
